Skip to content

ci: add explicit permissions to build-desktop workflow#1739

Closed
hobostay wants to merge 1 commit into
tinyhumansai:mainfrom
hobostay:fix/add-permissions-build-desktop
Closed

ci: add explicit permissions to build-desktop workflow#1739
hobostay wants to merge 1 commit into
tinyhumansai:mainfrom
hobostay:fix/add-permissions-build-desktop

Conversation

@hobostay
Copy link
Copy Markdown
Contributor

@hobostay hobostay commented May 14, 2026

Summary

  • Adds an explicit permissions block to .github/workflows/build-desktop.yml
  • Grants contents: read (checkout + Sentry debug file uploads) and actions: write (cache + artifact uploads)

Context

The build-desktop reusable workflow handles code signing secrets (Apple certificates, Tauri signing key, Sentry auth tokens) but was the only workflow in .github/workflows/ that did not declare explicit permissions. Without an explicit block, the workflow inherits the repository's default GITHUB_TOKEN permissions, which may be broader than necessary.

All other workflows in the repo already declare their permissions. This change aligns build-desktop.yml with the existing pattern and follows the principle of least privilege.

Test plan

  • Verify staging and production release workflows still trigger build-desktop correctly
  • Confirm actions/upload-artifact and actions/cache still work with actions: write

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Updated build workflow configuration to enhance build process security and permissions management.

Review Change Stack

The build-desktop reusable workflow handles code signing secrets (Apple
certificates, Tauri signing key, Sentry auth tokens) but does not
declare an explicit permissions block. Without one, the workflow runs
with the repository's default token permissions, which may be broader
than necessary.

Add explicit `contents: read` (for checkout + Sentry debug files) and
`actions: write` (for cache + artifact uploads) to follow the principle
of least privilege. All other workflows in the repo already declare
their permissions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hobostay hobostay requested a review from a team May 14, 2026 12:16
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

📝 Walkthrough

Walkthrough

The desktop build workflow gains an explicit top-level permissions configuration that restricts the GitHub Actions token to least-scope access: contents: read for reading repository contents and actions: write for modifying action-related resources during the build, upload, and signing operations.

Changes

Build Workflow Security

Layer / File(s) Summary
Workflow permissions block
.github/workflows/build-desktop.yml
Top-level permissions block added with contents: read and actions: write to restrict GitHub Actions token scope to only required access levels.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes

Poem

🐰 A permissions block, so neat and tight,
Read the contents, write actions—just right!
Least scope granted with minimal care,
Security strengthens the workflow we share!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding explicit permissions to the build-desktop workflow, which is the primary focus of this changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-desktop.yml:
- Around line 16-18: The workflow's permissions block currently sets "contents:
read" which will cause the gh release upload call (invoked by the step that runs
scripts/release/upload-macos-artifacts.sh and guarded by with_release_upload) to
fail with 403; change the workflow-level permissions to include "contents:
write" (or, if you prefer least-privilege, add step-level permissions: contents:
write specifically on the step that runs gh release upload /
scripts/release/upload-macos-artifacts.sh) and remove the unnecessary "actions:
write" scope.
- Around line 14-19: The YAML has `permissions:` incorrectly indented inside
`on.workflow_call`, which breaks parsing and orphanes `inputs:`; move the entire
`permissions:` block out to top-level (as a peer of `on:` and `jobs:`) after the
`on:` block so `on.workflow_call.inputs` remains nested correctly, and change
its scope to `contents: write` (remove the unnecessary `actions: write`) so
operations like `gh release upload` have the required write permission for
repository contents.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 761f11f8-88ba-4b9a-969d-6c22f2399c2e

📥 Commits

Reviewing files that changed from the base of the PR and between 1c58d47 and adba5db.

📒 Files selected for processing (1)
  • .github/workflows/build-desktop.yml

Comment on lines 14 to 19
on:
workflow_call:
permissions:
contents: read
actions: write
inputs:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Validate the workflow YAML and confirm workflow_call.inputs is populated.
python - <<'PY'
import sys, yaml
with open('.github/workflows/build-desktop.yml') as f:
    try:
        doc = yaml.safe_load(f)
    except yaml.YAMLError as e:
        print("YAML parse error:", e); sys.exit(1)
wc = (doc.get('on') or doc.get(True) or {}).get('workflow_call') or {}
print("workflow_call.inputs keys:", list((wc.get('inputs') or {}).keys()))
print("top-level permissions:", doc.get('permissions'))
PY

Repository: tinyhumansai/openhuman

Length of output: 183


🏁 Script executed:

# First, let's view the current build-desktop.yml around lines 14-25 to see exact indentation
sed -n '14,25p' .github/workflows/build-desktop.yml | cat -A

Repository: tinyhumansai/openhuman

Length of output: 321


🏁 Script executed:

# Now test the corrected structure by creating a test YAML and validating it
python - <<'PY'
import sys, yaml

# Read current file
with open('.github/workflows/build-desktop.yml', 'r') as f:
    content = f.read()
    
# Show what we have at lines 14-25
lines = content.split('\n')
print("Current lines 14-25:")
for i in range(13, min(25, len(lines))):
    print(f"{i+1:3d}: {repr(lines[i])}")

print("\n" + "="*60)
print("Attempting to parse current file:")
try:
    doc = yaml.safe_load(content)
    print("ERROR: File parsed successfully (unexpected!)")
except yaml.YAMLError as e:
    print(f"✓ Parse error confirmed: {e}")
PY

Repository: tinyhumansai/openhuman

Length of output: 648


🏁 Script executed:

# Find the line containing "inputs:" to understand the structure
grep -n "inputs:" .github/workflows/build-desktop.yml | head -5

Repository: tinyhumansai/openhuman

Length of output: 81


🏁 Script executed:

# Get broader context: lines 1-30
sed -n '1,30p' .github/workflows/build-desktop.yml | cat -n

Repository: tinyhumansai/openhuman

Length of output: 1391


🏁 Script executed:

# Find where the on: block ends (jobs: keyword marks next top-level section)
grep -n "^jobs:" .github/workflows/build-desktop.yml

Repository: tinyhumansai/openhuman

Length of output: 76


🏁 Script executed:

# Get lines around the end of the on: block (inputs section)
sed -n '90,105p' .github/workflows/build-desktop.yml | cat -n

Repository: tinyhumansai/openhuman

Length of output: 843


🏁 Script executed:

# Test the proposed fix by creating corrected YAML
python - <<'PY'
import yaml

# Create the corrected structure
corrected_yaml = """
on:
  workflow_call:
    inputs:
      build_ref:
        description: Git ref to check out for the build (tag or SHA).
        type: string
        required: true
permissions:
  contents: read
  actions: write
jobs:
  build:
    runs-on: ubuntu-latest
"""

print("Testing corrected YAML structure:")
try:
    doc = yaml.safe_load(corrected_yaml)
    wc = (doc.get('on') or {}).get('workflow_call') or {}
    print(f"✓ YAML parses successfully")
    print(f"  workflow_call.inputs keys: {list((wc.get('inputs') or {}).keys())}")
    print(f"  top-level permissions: {doc.get('permissions')}")
except yaml.YAMLError as e:
    print(f"✗ Parse error: {e}")
PY

Repository: tinyhumansai/openhuman

Length of output: 225


🏁 Script executed:

# Now check line 587 to understand what permission is needed for gh release upload
sed -n '580,595p' .github/workflows/build-desktop.yml | cat -n

Repository: tinyhumansai/openhuman

Length of output: 811


🏁 Script executed:

# Verify the permission scope: check if there are other uses of contents: write needed
grep -n "gh release\|contents: write\|actions: write" .github/workflows/build-desktop.yml

Repository: tinyhumansai/openhuman

Length of output: 180


🏁 Script executed:

# Check the current permission block in context (lines 13-20)
sed -n '13,20p' .github/workflows/build-desktop.yml | cat -n

Repository: tinyhumansai/openhuman

Length of output: 250


🏁 Script executed:

# Test what the corrected permissions should be
python - <<'PY'
import yaml

# Test with correct permissions scope
corrected_yaml_with_full_inputs = """
on:
  workflow_call:
    inputs:
      build_ref:
        description: Git ref
        type: string
        required: true
      with_updater:
        description: desc
        type: boolean
        default: true
permissions:
  contents: write
jobs:
  build:
    runs-on: ubuntu-latest
"""

print("Testing corrected YAML with contents: write (for gh release upload):")
try:
    doc = yaml.safe_load(corrected_yaml_with_full_inputs)
    wc = (doc.get('on') or {}).get('workflow_call') or {}
    inputs = list((wc.get('inputs') or {}).keys())
    perms = doc.get('permissions')
    print(f"✓ YAML parses successfully")
    print(f"  workflow_call.inputs keys: {inputs}")
    print(f"  top-level permissions: {perms}")
    if 'build_ref' in inputs and 'with_updater' in inputs:
        print(f"✓ All inputs properly nested under workflow_call")
except yaml.YAMLError as e:
    print(f"✗ Parse error: {e}")
PY

Repository: tinyhumansai/openhuman

Length of output: 241


🏁 Script executed:

# Check what the actual fix should look like - find exact end of inputs block
sed -n '95,102p' .github/workflows/build-desktop.yml | cat -A

Repository: tinyhumansai/openhuman

Length of output: 402


🏁 Script executed:

# Verify where inputs block ends to understand complete fix scope
sed -n '19,100p' .github/workflows/build-desktop.yml | grep -n "^ " | tail -1

Repository: tinyhumansai/openhuman

Length of output: 91


🏁 Script executed:

# Check what permissions release upload actually requires
python - <<'PY'
# According to GitHub Actions documentation:
# - actions/checkout@v4: needs contents:read
# - actions/cache@v5: does NOT require actions:write (uses its own service token)
# - actions/upload-artifact@v5: does NOT require actions:write (uses artifact service, not GITHUB_TOKEN for uploads)
# - gh release upload: needs contents:write (releases are part of repository contents)

# The workflow uses "gh release upload" at line 587, so:
print("Permission requirements for this workflow:")
print("- contents:read  (for actions/checkout)")
print("- contents:write (for gh release upload at line 587)")
print("- actions:write  (NOT needed for cache, checkout, or upload-artifact)")
print("\nConclusion: permissions should be 'contents: write' (or 'contents: read' if release upload is disabled)")
print("The current 'contents: read + actions: write' is WRONG for two reasons:")
print("  1. actions:write is unnecessary")
print("  2. contents:read is insufficient for gh release upload (needs write)")
PY

Repository: tinyhumansai/openhuman

Length of output: 554


🏁 Script executed:

# Final test: create a complete valid YAML structure matching the file
python - <<'PY'
import yaml

# Simulate the corrected structure with proper indentation
corrected = """---
name: Build Desktop (reusable)
on:
  workflow_call:
    inputs:
      build_ref:
        description: Git ref to check out for the build (tag or SHA).
        type: string
        required: true
      tag:
        description: Tag name
        type: string
        required: true
      with_updater:
        description: When true, set WITH_UPDATER=true
        type: boolean
        default: true
permissions:
  contents: write
jobs:
  build:
    runs-on: ubuntu-latest
"""

print("Testing corrected structure (with contents:write):")
try:
    doc = yaml.safe_load(corrected)
    on_block = doc.get('on') or {}
    wc = on_block.get('workflow_call') or {}
    inputs = wc.get('inputs') or {}
    perms = doc.get('permissions') or {}
    
    print(f"✓ YAML parses successfully")
    print(f"  on.workflow_call.inputs: {list(inputs.keys())}")
    print(f"  permissions: {perms}")
    print(f"  jobs: {list(doc.get('jobs', {}).keys())}")
except yaml.YAMLError as e:
    print(f"✗ Parse error: {e}")
PY

Repository: tinyhumansai/openhuman

Length of output: 229


🏁 Script executed:

# Confirm the end of the on: block and structure
sed -n '14,100p' .github/workflows/build-desktop.yml | grep -E "^(on:|  workflow_call:|permissions:|jobs:)" | head -5

Repository: tinyhumansai/openhuman

Length of output: 106


Critical: permissions: block is inserted inside on.workflow_call:, breaking YAML parsing and orphaning inputs:.

The file fails to parse with error "mapping values are not allowed here" at line 19. The current indentation places permissions: at column 0 between workflow_call: and inputs:, which closes the on: block before inputs: is defined. The inputs: key at column 4 becomes a stray orphaned entry. This breaks the reusable workflow contract, making it uncallable by the staging and production release workflows.

permissions: must be a top-level key (peer of on: / jobs:) placed after the entire on: block, not inside it.

Major: Permission scope is wrong and insufficient for gh release upload at line 587.

The current contents: read + actions: write is incorrect:

  • actions: write is unnecessary (actions/cache and actions/upload-artifact do not require it; they use service-scoped tokens).
  • contents: read is insufficient for gh release upload, which requires contents: write since releases are repository contents. The upload will fail with 403 Forbidden.

The permission block should use contents: write to support release uploads.

🛠️ Proposed fix — move `permissions:` to top level after `on:` block
 on:
   workflow_call:
     inputs:
       build_ref:
         description: Git ref to check out for the build (tag or SHA).
         type: string
         required: true
       tag:
         description:
           Tag name used by GH Release uploads (e.g. v1.2.4) and by the staging
           standalone CLI artifact name (e.g. v1.2.4-staging).
         type: string
         required: true
       with_updater:
         description:
           When true, set `WITH_UPDATER=true` so the Tauri bundler emits the
           signed `.sig` updater artifacts the auto-updater consumes.
           Production sets this and assembles `latest.json` in a follow-on
           job; staging leaves it off because there is no manifest publish
           step to consume the .sig files — producing them just wastes
           signing time and pollutes the artifact tree.
         type: boolean
         default: true
+permissions:
+  contents: write
 jobs:
🧰 Tools
🪛 actionlint (1.7.12)

[error] 19-19: could not parse as YAML: mapping values are not allowed in this context

(syntax-check)

🪛 YAMLlint (1.38.0)

[error] 19-19: syntax error: mapping values are not allowed here

(syntax)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-desktop.yml around lines 14 - 19, The YAML has
`permissions:` incorrectly indented inside `on.workflow_call`, which breaks
parsing and orphanes `inputs:`; move the entire `permissions:` block out to
top-level (as a peer of `on:` and `jobs:`) after the `on:` block so
`on.workflow_call.inputs` remains nested correctly, and change its scope to
`contents: write` (remove the unnecessary `actions: write`) so operations like
`gh release upload` have the required write permission for repository contents.

Comment on lines +16 to +18
permissions:
contents: read
actions: write
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What GITHUB_TOKEN permissions are required for actions/upload-artifact v5, actions/cache v5, and gh release upload in 2026?

💡 Result:

actions/upload-artifact@v5: contents: read (works even with empty permissions in private repos, but contents: read explicitly for safety) [1]. Official docs do not specify beyond general repo access, and artifact upload uses a special token but GITHUB_TOKEN needs contents: read for checkout/context [2][3]. actions/cache@v5: actions: write (for saving/restoring caches, as cache is managed under Actions API) [4][3]. Docs confirm no explicit permissions listed, but related tools require actions: read/write [5]. gh release upload: contents: write (required for creating/updating releases and uploading assets via REST API /releases endpoint) [6][7][8][9]. Uses GH_TOKEN which maps to contents permission for repo write operations including releases [10].

Citations:


🌐 Web query:

Does actions/cache@v5 use GITHUB_TOKEN or a separate cache service token? GitHub Actions permissions

💡 Result:

actions/cache@v5 uses the GITHUB_TOKEN (via ${{ github.token }} context) to access GitHub's built-in cache service. It does not require a separate cache service token. The action internally calls GitHub's REST API endpoints for Actions cache (e.g., list, get, create, update caches), which require the GITHUB_TOKEN to have actions:read (for restore) and actions:write (for save) permissions [1][2][3][4][5][6]. By default, GITHUB_TOKEN has these permissions unless restricted in the workflow [3][7]. No external cache service or additional token is needed or mentioned in official docs or the action's README [8][9][2][10][11]. For explicit cache management (e.g., delete via gh cache), actions:write must be granted [1][4][7].

Citations:


🌐 Web query:

GitHub Actions cache token mechanism in 2026 - GITHUB_TOKEN vs runner cache service

💡 Result:

In 2026, GitHub Actions caching uses an internal “Actions cache service” authentication token (ACTIONS_RUNTIME_TOKEN / bearer token), not the same credential that you normally use as GITHUB_TOKEN for GitHub API calls. 1) What GITHUB_TOKEN is (and is for) - GITHUB_TOKEN is the automatically generated token in a workflow job; it can be used for authenticated GitHub API calls and its permissions are controlled via the workflow’s permissions settings. It expires after the job completes and is scoped to the repository that contains the workflow.[1][2] 2) What the cache service token is (and is for) - The cache action (actions/cache) talks to GitHub’s cache backend service over an internal HTTP API. In the actions/toolkit cache HTTP client used by actions/cache, the client reads a token from the environment variable ACTIONS_RUNTIME_TOKEN and sends it as a Bearer credential in requests to the cache service.[3] - The Docker BuildKit “gha” cache backend docs likewise describe cache v2 inputs as coming from ACTIONS_RESULTS_URL and ACTIONS_RUNTIME_TOKEN, describing token “see authentication”.[4][5] 3) How the two differ in practice (GITHUB_TOKEN vs cache token) - GITHUB_TOKEN: intended for GitHub API authentication and is the token you reference as secrets.GITHUB_TOKEN / github.token.[2] - Cache service token (ACTIONS_RUNTIME_TOKEN): intended for calling the cache/artifacts/runtime service endpoints that actions/cache uses. It’s provided by the runner for workflow/action execution contexts, and it is the token wired into the cache HTTP client (Bearer) to access the cache service endpoints.[3][6] 4) Does actions/cache fall back to GITHUB_TOKEN? - The published toolkit cache client code shown above specifically uses ACTIONS_RUNTIME_TOKEN as the token it loads for cache service communication.[3] - I did not find an authoritative 2026 doc explicitly stating “ACTIONS_RUNTIME_TOKEN == GITHUB_TOKEN”. What is clearly documented is that cache actions depend on their runtime environment variables for cache service access, while GITHUB_TOKEN is for GitHub API authentication.[3][2][5] 5) Security boundary note (why GitHub doesn’t want you storing secrets in caches) - GitHub explicitly recommends not storing sensitive information (including access tokens/credentials) in cached files because cache contents can be accessed via pull requests from forks / readers.[7] Bottom line - Use GITHUB_TOKEN for GitHub API calls. - For GitHub Actions cache upload/download via actions/cache (and cache service v2 clients), the authentication mechanism is the bearer token provided to the runtime as ACTIONS_RUNTIME_TOKEN (with cache service URLs like ACTIONS_RESULTS_URL), not GITHUB_TOKEN by itself.[3][4][2]

Citations:


🌐 Web query:

Official GitHub documentation actions/cache@v5 GITHUB_TOKEN permissions requirements

💡 Result:

Official GitHub documentation / behavior: actions/cache@v5 doesn’t require you to pass GITHUB_TOKEN explicitly. GitHub Actions provides a GITHUB_TOKEN automatically to each job, and workflow/job permissions: controls what that token can do for the job [1][2]. What permissions: you need for actions/cache@v5: - To allow the GITHUB_TOKEN to create/save or manage GitHub Actions caches used by actions/cache, you generally need the actions scope to be writable: set permissions: actions: write (commonly alongside contents: read if you also check out code). - This is supported by GitHub’s mechanism for configuring GITHUB_TOKEN permissions via permissions: at the workflow/job level [2][3]. - Cache-related guidance indicates actions: write is needed for cache management operations that hit the Actions cache REST API (e.g., delete or other operations beyond restore). For example, a documented fix states permissions: actions: write as the needed setting [4]. - GitHub Actions “actions cache” operations (like delete) also reference actions:write as the required permission in practice [5]. Example (least privilege for typical cache usage + checkout): - Job-level permissions: - contents: read - actions: write Notes / gotchas: - GITHUB_TOKEN is a GitHub App installation access token whose permissions are limited; you can control those permissions with permissions: [1][6]. - Forked pull requests are treated specially and may receive reduced GITHUB_TOKEN permissions (often read-only), which can restrict cache write/save behavior depending on the trigger/context [6][7].

Citations:


🏁 Script executed:

# Check if the file exists and read the relevant sections
if [ -f ".github/workflows/build-desktop.yml" ]; then
  echo "=== Permissions block (lines 16-18) ==="
  sed -n '15,20p' .github/workflows/build-desktop.yml
  
  echo -e "\n=== gh release upload at line 587 ==="
  sed -n '585,590p' .github/workflows/build-desktop.yml
  
  echo -e "\n=== macOS re-upload script at line 657 ==="
  sed -n '655,660p' .github/workflows/build-desktop.yml
  
  echo -e "\n=== All uses of gh release or release upload ==="
  grep -n "gh release\|release.*upload" .github/workflows/build-desktop.yml || echo "No matches found"
else
  echo "File not found"
fi

Repository: tinyhumansai/openhuman

Length of output: 1621


🏁 Script executed:

# Also check if actions/cache and actions/upload-artifact are used
echo "=== Actions used in workflow ==="
grep -n "uses.*actions/cache\|uses.*actions/upload-artifact" .github/workflows/build-desktop.yml || echo "Not found"

Repository: tinyhumansai/openhuman

Length of output: 364


Fix permissions block: contents: write required for gh release upload (line 587) — current contents: read will fail with 403.

The workflow calls gh release upload at line 587 and via scripts/release/upload-macos-artifacts.sh, which requires contents: write on the releases API. With only contents: read, release uploads will fail on the first run with with_release_upload: true.

The actions: write scope is unnecessary. While actions/cache@v5 appears in this workflow (5 times), it uses the runner's internal ACTIONS_RUNTIME_TOKEN, not GITHUB_TOKEN permissions—the cache service operates independently of the permissions: block.

Minimal correct set:

🛡️ Corrected scopes
 permissions:
-  contents: read
-  actions: write
+  contents: write

If you prefer least-privilege granularity, scope contents: write only to the release upload steps via step-level permissions: and leave the workflow default at contents: read.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
permissions:
contents: read
actions: write
permissions:
contents: write
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-desktop.yml around lines 16 - 18, The workflow's
permissions block currently sets "contents: read" which will cause the gh
release upload call (invoked by the step that runs
scripts/release/upload-macos-artifacts.sh and guarded by with_release_upload) to
fail with 403; change the workflow-level permissions to include "contents:
write" (or, if you prefer least-privilege, add step-level permissions: contents:
write specifically on the step that runs gh release upload /
scripts/release/upload-macos-artifacts.sh) and remove the unnecessary "actions:
write" scope.

@senamakel
Copy link
Copy Markdown
Member

hey appreciate the PR but coderabbit raises some valid concerns here.. also the build-desktop is really a tempalte script so it's never run on it's own. but often as part of another script which has permissions properly set. thanks for submitting though, feel free to pick up another issue instaed 🙏

@senamakel senamakel closed this May 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants